#include "campus_wss_server.h"
#include "../log/campus_logger.h"

CampusWssServer::CampusWssServer(int port):
    port_(port)
{
}

CampusWssServer::~CampusWssServer()
{
    if(thread_ && thread_->joinable()){
        thread_->join();
    }
    if(thread_){
        delete thread_;
    }
    thread_ = nullptr;
}

int CampusWssServer::wait()
{
    if(thread_ && thread_->joinable()){
        thread_->join();
        return 0;
    }
    else{
        return 1;
    }
}

void CampusWssServer::on_open(server* s, websocketpp::connection_hdl hdl)
{
    connection_list_.push_back(hdl);
    CampusLogger::info("on_open called with hdl: {}", hdl.lock().get());
}

void CampusWssServer::on_close(server* s, websocketpp::connection_hdl hdl)
{
    CampusLogger::info("connection_list_ size = {}", connection_list_.size());
    // 清理连接列表
    for (auto it = connection_list_.begin(); it != connection_list_.end();)
    {
        CampusLogger::info("connection = {}", it->lock().get());
        if (it->expired() || it->lock() == hdl.lock()) //断开自己
        {
            it = connection_list_.erase(it);
            CampusLogger::info("connection_list_ erase");
        }
        else
        {
            ++it;
        }
    }
}

void CampusWssServer::on_fail(websocketpp::connection_hdl hdl){
    CampusLogger::info("on_fail called with hdl: {}", hdl.lock().get());
}

void CampusWssServer::on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg)
{
    std::string msg_str = msg->get_payload();
    CampusLogger::info("on_message: {}", msg_str);
}

int CampusWssServer::init()
{
     try {
        //打印所有日志
        server_.set_access_channels(websocketpp::log::alevel::all);
        server_.clear_access_channels(websocketpp::log::alevel::all);
        
        // 初始化ASIO
        server_.init_asio();
        
        // 设置TLS处理器
        server_.set_tls_init_handler(bind(&CampusWssServer::on_tls_init,this));
        
        // 注册回调函数
        server_.set_open_handler(bind(&CampusWssServer::on_open, this,&server_, ::_1));
        server_.set_close_handler(bind(&CampusWssServer::on_close,this, &server_, ::_1));
        server_.set_fail_handler(bind(&CampusWssServer::on_fail, this, ::_1));
        server_.set_message_handler(bind(&CampusWssServer::on_message,this,&server_, ::_1, ::_2));

        //监听端口
        server_.listen(port_);
    }
     catch (const std::exception& e) {
        CampusLogger::warn("wss server init failed ! {}", e.what());
    }

    return 0;
}

int CampusWssServer::send(websocketpp::connection_hdl hdl, const std::string msg)
{
    std::lock_guard<std::mutex> lock(mutex_);
    if(hdl.expired()){
        CampusLogger::warn("send failed: hdl has expired !");
        return 1;
    }
    else{
        CampusLogger::info("send msg = {}", msg);
        server_.send(hdl, msg, websocketpp::frame::opcode::text);
    }
    return 0;
}

int CampusWssServer::run()
{
    if(running_){
        CampusLogger::warn("server has been running !");
        return 1;
    }
    thread_ = new std::thread([this](){
        try{
        server_.start_accept();
        CampusLogger::info("WSS服务器运行在端口 {}", port_);

        server_.run();
        }catch(...){
            CampusLogger::warn("server exec failed !");
        }
    });


    return 0;
}

context_ptr CampusWssServer::on_tls_init()
{
namespace asio_ssl = boost::asio::ssl;
    // context_ptr ctx = std::make_shared<asio_ssl::context>(asio_ssl::context::tlsv12_server);
   context_ptr ctx = std::make_shared<asio_ssl::context>(asio_ssl::context::tls); 
    try {
        // 设置安全协议选项
        ctx->set_options(
            asio_ssl::context::default_workarounds |
            asio_ssl::context::no_sslv2 |
            asio_ssl::context::no_sslv3 |
            asio_ssl::context::no_tlsv1 |
            asio_ssl::context::no_tlsv1_1 |
            asio_ssl::context::single_dh_use
        );
        
        // 加载证书和私钥
        ctx->use_certificate_chain_file("/home/liuhang/cert/cert.pem");
        ctx->use_private_key_file("/home/liuhang/cert/key.pem", asio_ssl::context::pem);
        
        // 验证密钥匹配
        if (!SSL_CTX_check_private_key(ctx->native_handle())) {
            CampusLogger::warn("错误: 证书和私钥不匹配");
            throw std::runtime_error("证书/私钥不匹配");
        }
        
        // 设置密码套件
        SSL_CTX_set_cipher_list(ctx->native_handle(), "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4");
        
        CampusLogger::info("TLS上下文初始化成功");
    } catch (std::exception& e) {
        CampusLogger::warn("TLS初始化失败: {}", e.what());
        exit(1);
    }
    return ctx;
}
